package cn.tedu.lbs.basic.web.service;

import cn.tedu.lbs.basic.web.repository.AdminRepository;
import cn.tedu.lbs.basic.web.repository.BusinessCategoryRepository;
import cn.tedu.lbs.basic.web.repository.BusinessRepository;
import cn.tedu.lbs.basic.web.repository.StoreRepository;
import cn.tedu.lbs.basic.web.utils.AuthenticationContextUtil;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.tarena.lbs.attach.api.AttachApi;
import com.tarena.lbs.base.common.utils.Asserts;
import com.tarena.lbs.base.protocol.exception.BusinessException;
import com.tarena.lbs.base.protocol.pager.PageResult;
import com.tarena.lbs.common.passport.enums.Roles;
import com.tarena.lbs.common.passport.principle.UserPrinciple;
import com.tarena.lbs.pojo.attach.param.PicUpdateParam;
import com.tarena.lbs.pojo.basic.param.BusinessParam;
import com.tarena.lbs.pojo.basic.po.AdminPO;
import com.tarena.lbs.pojo.basic.po.BusinessPO;
import com.tarena.lbs.pojo.basic.po.StorePO;
import com.tarena.lbs.pojo.basic.query.BusinessQuery;
import com.tarena.lbs.pojo.basic.vo.BusiStoreVO;
import com.tarena.lbs.pojo.basic.vo.BusinessCategoryVO;
import com.tarena.lbs.pojo.basic.vo.BusinessVO;
import com.tarena.lbs.pojo.basic.vo.StoreVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class BusinessService {
    @Autowired
    private BusinessRepository businessRepository;
    @Autowired
    private AdminRepository adminRepository;
    @Autowired
    private StoreRepository storeRepository;
    private Integer checkRoleAndGetBusinessId() throws BusinessException {
        Integer businessId=null;
        //1.拿到认证对象
        UserPrinciple userPrinciple = AuthenticationContextUtil.get();
        //2.断言 非空
        Asserts.isTrue(userPrinciple==null,new BusinessException("-2","用户认证解析失败"));
        //3.判断是否是SHOP 是SHOP 使用user的id 查询admin表格获取businessId关联的商家id返回
        if (userPrinciple.getRole()== Roles.SHOP){
            Integer adminId = userPrinciple.getId();
            //查询lbs_admin表格 adminPO 获取businessId
            AdminPO po = adminRepository.getById(adminId);
            Asserts.isTrue(po==null,new BusinessException("-2","用户信息解析失败"));
            businessId=po.getBusinessId();
            log.info("查询商家账号的关联商家id;入参:{},出参:{}",adminId,businessId);
        }
        return businessId;
    }
    public PageResult<BusinessVO> pageList(BusinessQuery query) throws BusinessException {
        //在分页查询之前,检查当前登录用户 获取businessId
        Integer businessId=checkRoleAndGetBusinessId();
        query.setBusinessId(businessId);
        //1.准备一个pageResult对象
        PageResult<BusinessVO> pageResult=new PageResult<>();
        pageResult.setPageNo(query.getPageNo());
        pageResult.setPageSize(query.getPageSize());
        //2.缺什么给什么 pageNo(query) pageSize(query) total(BusinessMapper count)
        // objects(List<BusinessVO> businessMapper List<BusinessPO> -> BusinessVO)
        //2.1 total sql select count(0) from lbs_business where 非空拼接 商家名称 负责人电话 时间范围
        //Long total=getTotal(query);
        //2.2 object select * from lbs_business where 非空拼接 商家名称 负责人电话 时间范围 limit from,size
        //List<BusinessVO> vos=getObjects(query);
        //pageResult.setTotal(total);
        //pageResult.setObjects(vos);
        PageInfo<BusinessPO> pageInfo = getPageInfo(query);
        //pageInfo有分页使用的所有属性 pageNo pageSize total objects
        pageResult.setTotal(pageInfo.getTotal());
        //从pageInfo获取本次分页查询的列表 pos
        List<BusinessPO> pos = pageInfo.getList();
        List<BusinessVO> vos=null;
        if (pos!=null&&pos.size()>0){
            //使用原集合pos做流映射处理
            vos=pos.stream().map(po->{
                //TODO映射算法 返回新映射对象
                BusinessVO vo=new BusinessVO();
                BeanUtils.copyProperties(po,vo);
                return vo;
            }).collect(Collectors.toList());
        }
        pageResult.setObjects(vos);
        return pageResult;
    }

    private PageInfo<BusinessPO> getPageInfo(BusinessQuery query) {
        //希望通过 pageHelper查询 将属性total和objects全部查询出来 返回
        //以下 严格遵循分页插件PageHelper的使用
        //1.开启分页
        PageHelper.startPage(query.getPageNo(),query.getPageSize());
        /*if(1==1){
            PageHelper.clearPage();
            return null;
        }*/
        //2.开启业务查询 只关心业务条件的 sql select * from lbs_business where query非空条件
        QueryWrapper<BusinessPO> queryWrapper= generateQueryWrapper(query);
        List<BusinessPO> pos = businessRepository.list(queryWrapper);
        //pos实现类 已经不在是mybatis封装的 ArrayList 是一个Page对象
        log.info("分页插件PageHelper查询结果类型：{}",pos.getClass().getName());
        //3.将开启了分页查询的结果 pos对象 交给插件的类型封装
        return new PageInfo(pos);

    }

    private QueryWrapper<BusinessPO> generateQueryWrapper(BusinessQuery query) {
        QueryWrapper<BusinessPO> queryWrapper=new QueryWrapper<>();
        //根据query参数中的非空属性 拼接where
        if (query.getBusinessName()!=null){
            //where business_name like '%?%'
            queryWrapper.like("business_name",query.getBusinessName());
        }
        if (query.getBusinessHeadPhone()!=null){
            queryWrapper.eq("business_head_phone",query.getBusinessHeadPhone());
        }
        if (query.getBusinessStatus()!=null){
            queryWrapper.eq("business_status",query.getBusinessStatus());
        }
        if (query.getStartingTime()!=null){
            //where entry_time >= ? ge(greater than and equals) le(less than and equals)
            queryWrapper.ge("entry_time",query.getStartingTime());
        }
        if (query.getEndTime()!=null){
            queryWrapper.le("entry_time",query.getEndTime());
        }
        if (query.getBusinessId()!=null){
            log.info("拼接查询商家条件,入参:{},商家账号查询单个商家",query);
            queryWrapper.eq("id",query.getBusinessId());
        }
        return queryWrapper;
    }
    @Autowired
    private BusinessCategoryRepository businessCategoryRepository;
    public List<BusinessCategoryVO> categoryList() {
        return businessCategoryRepository.list().stream().map(po->{
            BusinessCategoryVO vo=new BusinessCategoryVO();
            BeanUtils.copyProperties(po,vo);
            return vo;
        }).collect(Collectors.toList());
    }
    @Transactional(rollbackFor = Exception.class)//默认只回滚RuntimeException
    public void save(BusinessParam param) throws BusinessException {
        //1.检查业务权限
        checkRole(Roles.ADMIN);
        //2.幂等的新增逻辑
        Integer id=saveOnce(param);
        //3.绑定图片逻辑

        bindPictures(param,id);



    }
    @DubboReference
    private AttachApi attachApi;
    private void bindPictures(BusinessParam param,Integer bizId) throws BusinessException {
        log.info("图片客户端api 实现类:{}",attachApi.getClass().getName());
        //1.封装 绑定图片参数 logo license营业执照
        List<PicUpdateParam> params=new ArrayList<>();
        PicUpdateParam licenseParam=new PicUpdateParam();
        //每个封装 bizType=100 bizId=bizId id拿不到 fileUuid
        licenseParam.setBusinessType(100);
        licenseParam.setBusinessId(bizId);
        //fileUuid 在param入参 url地址 http://localhost:9081/static/af02139f31-f23.png
        licenseParam.setFileUuid(param.getBusinessLicense().split("/")[4]);
        params.add(licenseParam);
        PicUpdateParam logoParam=new PicUpdateParam();
        logoParam.setBusinessType(200);
        logoParam.setBusinessId(bizId);
        logoParam.setFileUuid(param.getBusinessLogo().split("/")[4]);
        params.add(logoParam);
        //2.远程调用 考虑失败的问题 远程连接 超时 连不上  业务失败 对方返回false
        try{
            boolean result = attachApi.batchUpdateBusiness(params);
            //概率几乎为零 但是可能发生
            if (!result){
                throw new BusinessException("-2","图片绑定失败了");
            }
        }catch (Exception e){
            log.error("远程调用失败",e);
            throw new BusinessException("-2","图片绑定失败了");
        }


    }

    private Integer saveOnce(BusinessParam param) throws BusinessException {
        //线程安全隐患 存在的三个因素
        //a 多线程并发(多个平台管理员 新增)
        //b 共享数据(同一个商家)  现在的业务 不会出现 多个管理员同时新增一个商家
        //c 写操作(增 删 改)
        //insert 数据到 lbs_business表格 幂等条件 是不允许出现相同名称的商家
        //方案思路: 新增写业务 设计幂等 先查 后写 在业务拦截判断
        QueryWrapper queryWrapper=new QueryWrapper();
        queryWrapper.eq("business_name",param.getBusinessName());
        //select count(0) from lbs_business where business_name=?
        long count=businessRepository.count(queryWrapper);
        //断言
        Asserts.isTrue(count>0,new BusinessException("-2","商家名称重复"));
        //表单数据 不是 100%满足 po对象属性要求 手动准备封装
        BusinessPO poParam=new BusinessPO();
        BeanUtils.copyProperties(param,poParam);
        //手动补充3个 状态 2 审核通过 entryTime now auditMark 审核意见
        poParam.setBusinessStatus(2);
        poParam.setEntryTime(new Date());
        poParam.setAuditRemarks("同意");
        businessRepository.save(poParam);
        //持久层框架 mybatis mybatis-plus 根据主键id自增设置 新增成功后 回填id
        return poParam.getId();
    }

    private void checkRole(Roles role) throws BusinessException {
        //读取 认证 传递的userPrinciple 线程和过滤器线程相同
        UserPrinciple userPrinciple = AuthenticationContextUtil.get();
        Asserts.isTrue(userPrinciple==null,new BusinessException("-2","用户认证解析失败"));
        //判断 对象非空的时候 是否和role相等
        Asserts.isTrue(userPrinciple.getRole()!=role,new BusinessException("-2","业务权限不满足"));
    }

    public BusiStoreVO busiStore(Integer id) {
        //1.查询商家详情
        BusinessPO po = businessRepository.getById(id);
        //2.不为空的时候 补充查询店铺列表信息 转化volist
        if (po!=null){
            BusiStoreVO vo=new BusiStoreVO();
            BeanUtils.copyProperties(po,vo);
            //select * from lbs_store where business_id=?
            QueryWrapper<StorePO> queryWrapper=new QueryWrapper<>();
            queryWrapper.eq("business_id",id);
            List<StorePO> storePos = storeRepository.list(queryWrapper);
            if (CollectionUtils.isNotEmpty(storePos)){
                vo.setStoreVOList(storePos.stream().map(storePO -> {
                    StoreVO storeVO = new StoreVO();
                    BeanUtils.copyProperties(storePO, storeVO);
                    return storeVO;
                }).collect(Collectors.toList()));
            }
            return vo;
        }else{
            return null;
        }
    }
}
